#include <stdlib.h>
#include <stdio.h>
#include <string.h>


/*****************************************
**  Zone de déclaration des constantes  **
*****************************************/
#define MAXSIZE 20
#define Fic_Regles "Regles"
#define Fic_Faits "Faits"	
#define TRUE 1
#define FALSE 0	


/*****************************************
**  Zone de déclaration des structures  **
*****************************************/
typedef struct CONDITION
{
	char cond[MAXSIZE];
	struct CONDITION *suiv; 
} ST_COND;

typedef struct FAITS
{
	char fait[MAXSIZE];
	struct FAITS *suiv; 
} ST_FAITS;

typedef struct RESULTAT
{
	char res[MAXSIZE];
	ST_COND* TeteListCond;
	struct RESULTAT *suiv;
} ST_RES;

/*****************************************
**  Zone de déclaration des Prototypes  **
*****************************************/
FILE* OuvrirFic(char* NomFic, char* mode);
ST_COND* Creer_MaillonCond(ST_COND* pt_tete, char* str);
ST_RES* Creer_MaillonRes(ST_RES* pt_tete, ST_COND* Tete_Cond, char* str);
ST_FAITS* Creer_MaillonFaits(ST_FAITS* pt_tete, char* str);
void AfficherListe(char indic);
void FreeListe(char indic);
void FermerFichier(FILE* fp);
void LireBases(char indic, FILE* fp);

int ChainArr_RecupBut (char* But,ST_RES* res_tete);
int ChainArr_VerifBut (char* But,ST_RES* res_tete,ST_FAITS* fait_tete);
int ChainArr_VerifFait (char* But,ST_FAITS* fait_tete);


/*************************************************
**  Zone de déclaration des variables globales  **
*************************************************/
ST_RES *Tete_Res=NULL;
ST_FAITS *Tete_Faits=NULL;

/**************************
**  Programme principal  **
**************************/
int main(void)
{
	FILE *fp=NULL;
	//////
	char But[MAXSIZE];
	//////
	
	
	fp=OuvrirFic(Fic_Regles,"r");
	if(fp!=NULL)
	{
		LireBases('R',fp);
		FermerFichier(fp);
		AfficherListe('R');
	}
	
	fp=OuvrirFic(Fic_Faits,"r");
	if(fp!=NULL)
	{
		LireBases('F',fp);
		FermerFichier(fp);
		AfficherListe('F');
	}
	
	printf("\n-------------------------------------\n\n");

	if(ChainArr_VerifBut (But,Tete_Res,Tete_Faits))
		printf("Valeur demontre !!!\n");
	else
		printf("Valeur non demontre ...\n");
	
	printf("Nouveau fait : \n");
	AfficherListe('F');
	//AfficherListe('R');
	
	FreeListe('R');
	FreeListe('F');
	return 0;
}

/***********************************************************************
**  [Fonction LireBases]					      **
**    Lit les fichiers de bases et les transforme en listes chainées  **
**    selon le type indiqué par indic ("r"=regles / "f"=faits)	      **
***********************************************************************/
void LireBases(char indic, FILE* fp)
{
	int flag=0;
	char mot[MAXSIZE];
	ST_COND *Tete_Cond=NULL;
	memset(mot,0,MAXSIZE*sizeof(char));
	
	if(indic=='f' || indic=='F')
	{
		while((fscanf(fp," %s", mot))!=EOF) //fscanf lit while(mot!=' ')
		{   
			if(mot[(strlen(mot)-1)]==';')
				mot[(strlen(mot)-1)]='\0';
			Tete_Faits=Creer_MaillonFaits(Tete_Faits,mot);		
		}
	}
	else if(indic=='r' || indic=='R')
	{
		while((fscanf(fp," %s", mot))!=EOF) //fscanf lit while(mot!=' ')
		{   
			if(!strcmp(mot,"->"))
				flag=1;
		
			if(flag==0)
				Tete_Cond=Creer_MaillonCond(Tete_Cond,mot);	
			else
			{
				if((fscanf(fp," %s", mot))!=EOF)
				{
					if(mot[(strlen(mot)-1)]==';')
						mot[(strlen(mot)-1)]='\0';
					Tete_Res=Creer_MaillonRes(Tete_Res,Tete_Cond,mot);
				}
				flag=0;
				Tete_Cond=NULL;
			}		
		}
	}
}

/******************************************************************
**  [Fonction Creer_MaillonCond]			         **
**    Créer le maillon pour une condition dans la liste chainée  **
**    des regles  					         **
******************************************************************/
ST_COND* Creer_MaillonCond(ST_COND* pt_tete, char* str)
{  
	ST_COND *new=NULL, *tmp=NULL;
	
	new=(ST_COND*)malloc(sizeof(ST_COND));
	memset(new->cond,0,MAXSIZE*sizeof(char));
	strcpy(new->cond, str);
	new->suiv=NULL;
	
	if(pt_tete==NULL){ 
		//si liste vide ajout en tete
		new->suiv=pt_tete;
		pt_tete=new;
	}
	else{ 
		//sinon ajout en fin
		tmp=pt_tete;
		while(tmp->suiv!=NULL)
			tmp=tmp->suiv;
		
		tmp->suiv=new;
	}
	return pt_tete;
}

/****************************************************************
**  [Fonction Creer_MaillonRes]				       **
**    Créer le maillon pour un résultat dans la liste chainée  **
**    des regles  					       **
****************************************************************/
ST_RES* Creer_MaillonRes(ST_RES* pt_tete, ST_COND* Tete_Cond, char* str)
{  
	ST_RES *new=NULL, *tmp=NULL;
	
	new=(ST_RES*)malloc(sizeof(ST_RES));
	memset(new->res,0,MAXSIZE*sizeof(char));
	strcpy(new->res, str);
	new->suiv=NULL;
	new->TeteListCond=Tete_Cond;
	
	if(pt_tete==NULL){
		//si liste vide ajout en tete
		new->suiv=pt_tete;
		pt_tete=new;
	}
	else {
		//sinon ajout en fin
		tmp=pt_tete;
		while(tmp->suiv!=NULL)
			tmp=tmp->suiv;
		
		tmp->suiv=new;
	}
	return pt_tete;
}

/************************************************************
**  [Fonction Creer_MaillonFaits]			   **
**    Créer le maillon pour un fait dans la liste chainée  **
**    des faits  					   **
************************************************************/
ST_FAITS* Creer_MaillonFaits(ST_FAITS* pt_tete, char* str)
{  
	ST_FAITS *new=NULL, *tmp=NULL;
	
	new=(ST_FAITS*)malloc(sizeof(ST_FAITS));
	memset(new->fait,0,MAXSIZE*sizeof(char));
	strcpy(new->fait, str);
	new->suiv=NULL;
	
	if(pt_tete==NULL){
		//si liste vide ajout en tete
		new->suiv=pt_tete;
		pt_tete=new;
	}
	else {
		//sinon ajout en fin
		tmp=pt_tete;
		while(tmp->suiv!=NULL)
			tmp=tmp->suiv;
		
		tmp->suiv=new;
	}
	return pt_tete;
}

/*********************************************************
**  [Fonction OuvrirFic]				**
**    Ouvre le fichier passé en paramètre dans le mode	**
**    spécifié en paramètre par la variable mode	**
*********************************************************/
FILE* OuvrirFic(char* NomFic,char* mode)
{
	FILE* f=NULL;
	if ((f = fopen(NomFic, mode)) == NULL)
	{
		printf("Erreur d'ouverture du fichier %s !\n",NomFic);
		return NULL;
		//exit(qqch) ??
	}
	else
		return f;
}

/********************************************
**  [Fonction FermerFichier]		   **
**    Ferme le fichier passé en paramètre  **
********************************************/
void FermerFichier(FILE* fp)
{
	if(fclose(fp))
		printf("Erreur fermeture\n");	
}

/*********************************************************
**  [Fonction FreeListeRegles]		   		**
**    Supprime tous les maillons de la liste chainée    **
**    indiquée par indic ("R"=Regles / "F"=Faits)       **
*********************************************************/
void FreeListe(char indic)
{
	ST_RES* tmpR=Tete_Res;
	ST_RES* tmpR2=NULL;
	ST_COND* tmpC=Tete_Res->TeteListCond;
	ST_COND* tmpC2=NULL;
	ST_FAITS* tmp=Tete_Faits;
	ST_FAITS* tmp2=NULL;
	
	if(indic=='R' || indic=='r')
	{
		while(tmpR!=NULL){
			tmpR2=tmpR->suiv;
			while(tmpC!=NULL){
				tmpC2=tmpC->suiv;
				free(tmpC);
				tmpC=tmpC2;
			}
			free(tmpR);
			tmpR=tmpR2;
		}
	}
	else if(indic=='F' || indic=='f')
	{
		while(tmp!=NULL){
			tmp2=tmp->suiv;
			free(tmp);
			tmp=tmp2;
		}
	}
}

/********************************************************
**  [Fonction AfficherListe]		   	       **
**    Affiche tous les maillons de la liste chainée    **
**    indiquée par indic ("R"=Regles / "F"=Faits)      **
********************************************************/
void AfficherListe(char indic)
{
	ST_RES *R=NULL;
	ST_COND *C=NULL;
	ST_FAITS *F=NULL;
	
	if(indic=='R' || indic=='r')
	{
		printf(">AFFICHAGE LISTE REGLES\n");
		R=Tete_Res;
		while(R!=NULL)
		{
			C=R->TeteListCond;
			printf("  -Resultat : [%s]\n",R->res);
			while(C!=NULL)
			{
				printf("    ->Condition : <%s>\n",C->cond);
				C=C->suiv;
			}
			R=R->suiv;
		}
	}
	else if(indic=='F' || indic=='f')
	{
		printf(">AFFICHAGE LISTE FAITS\n");
		F=Tete_Faits;
		while(F!=NULL)
		{
			printf("  -Fait : [%s]\n",F->fait);
			F=F->suiv;
		}
	}
	printf("\n");
}



/*************************************************************************
**  [Fonction ChainArr_VerifBut]                      					**
**  Moteur principal du chainage arriere						        **
**																		**
**	Entrees : Char* Tableau contenant le BUT                            **
**			: ST_RES* Tete de la chaine de resultats					**
**			: ST_FAITS* Tete de la chaine de faits						**
**																		**
**	Sorties : int														**
**				0 Le But n'est pas demontre                             **
**				1 Le But est valide                                 	**
**				-2 Erreur de chaine										**
**************************************************************************/
int ChainArr_VerifBut (char* But,ST_RES* res_tete,ST_FAITS* fait_tete)
{
	int result = 0;//Resultat de la recherche
	ST_RES *R=NULL;
	ST_COND *Hypothese=NULL;
	int Continue;
	if(strlen(But)==0)
		ChainArr_RecupBut (But,res_tete);				//Recupere la but a chercher

	printf("But : <%s>\n",But);
	if(res_tete==NULL || fait_tete == NULL)				//si liste vide Erreur	
		return -2;
	if(!ChainArr_VerifFait (But,fait_tete))				//Verifie si le But courant est compris dans les fait
	{
		R = res_tete;
		while(R!=NULL && result == 0)					//Boucle tant que Regle != de null et result FAUX
		{			
			if(strcmp(But,R->res) !=  0)
				printf("Le resultat (%s) ne fait pas partie des résultats_regles (%s)\n",R->res,But);
			else
			{
				printf("Le resultat (%s) fait partie des résultats_regles (%s)\n",R->res,But);
				Hypothese = R->TeteListCond;
				Continue = TRUE;
				while(Hypothese != NULL && Continue)
				{	
					Continue = ChainArr_VerifBut (Hypothese->cond,res_tete,fait_tete);
					Hypothese = Hypothese->suiv;
				}
				result = Continue;
				if(result == 1)
				{
					printf("Condition :%s valide\n",But);	
					Creer_MaillonFaits(fait_tete, But);
					AfficherListe('F');
				}
			}
			R=R->suiv;
		}
	}
	else
	{
		result = TRUE;
		printf("%s est un fait\n",But);
	}
		return result;								
}

/*************************************************
**  Zone de déclaration des Fonctions PRIVE     **
*************************************************/

/*************************************************************************
**  [Fonction ChainArr_RecupBut]                     					**
**  Récupere le but a demontrer depuis l'interface utilisateur          **
**																		**
**	Entrees : Char* Tableau contenant le BUT                            **
**			: ST_RES* Tete de la chaine de resultats					**
**																		**
**	Sorties : int														**
**				0 But correctement recupere                             **
**				-1 Erreur de memoire                                    **
**************************************************************************/
int ChainArr_RecupBut (char* But,ST_RES* res_tete)
{
	if(res_tete==NULL)//si liste vide Erreur	
		return -2;	
	memset(But,0,MAXSIZE*sizeof(char));
	scanf("%s",But);
	printf("Votre recherche : %s\n",But);
	return 0;
}


/*************************************************************************
**  [ChainArr_VerifFait]    		                  					**
**  Verifie si le Bur est dans les faits						        **
**																		**
**	Entrees : Char* Tableau contenant le BUT                            **
**			: ST_FAITS* Tete de la chaine de faits						**
**																		**
**	Sorties : int														**
**				0 Le But est un fait		                            **
**				1 Le But n'est pas un fait                            	**
**				-2 Erreur de chaine										**
**************************************************************************/
int ChainArr_VerifFait (char* But,ST_FAITS* fait_tete)
{
	int result = 0;//Resultat de la recherche
	ST_FAITS *F=NULL;
	
	if(fait_tete==NULL)//si liste vide Erreur	
		return -2;

	F = fait_tete;
	while(F!=NULL && result == 0)
		{
			if(strcmp(F->fait,But) != 0)
			{
				printf(" %s != %s\n",F->fait,But);
				result = 0;
			}
			else
			{
				printf(" %s = %s\n",F->fait,But);
				result = 1;
			}
			F=F->suiv;
		}
	return result;
}
